package pos.Driving.Train;

import javax.media.j3d.*;
import javax.vecmath.*;
import pos.utils.*;

/**
 *
 * @author plus
 */
public class Door extends TransformGroup implements Invokeable{
    private Train myTrain;
    private TransformGroup tgDoorA, tgDoorB;
    private Transform3D t3dDoorA,t3dDoorB;
    private Group gpLight;
    private Appearance appLight;
    private final static int DOOR_CLOSED=0, DOOR_CLOSING=1,
            DOOR_OPENING=2, DOOR_OPENED=3;
    private int currentState=DOOR_CLOSED;
    private double step=0;
    
    public Door(Transform3D t3d,String doorAKey,String doorBKey, String lightKey, Train train) {
        super(t3d);
        myTrain=train;
        t3dDoorA=new Transform3D();
        t3dDoorB=new Transform3D();
        tgDoorA=new TransformGroup(t3dDoorA);
        tgDoorB=new TransformGroup(t3dDoorB);
        tgDoorA.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        tgDoorB.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        gpLight=ObjectFactory.createObject(lightKey);
        lightMaterialFix(gpLight);
        tgDoorA.addChild(ObjectFactory.createObject(doorAKey));
        tgDoorB.addChild(ObjectFactory.createObject(doorBKey));
        defColorMaterialSet(tgDoorA);
        defColorMaterialSet(tgDoorB);
        addChild(gpLight);
        addChild(tgDoorA);
        addChild(tgDoorB);
    }
    
    public Door(Transform3D t3d,Door src,Train train) {
        super(t3d);
        myTrain=train;
        t3dDoorA=new Transform3D();
        t3dDoorB=new Transform3D();
        tgDoorA=new TransformGroup(t3dDoorA);
        tgDoorB=new TransformGroup(t3dDoorB);
        tgDoorA.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        tgDoorB.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        gpLight=(Group)src.gpLight.cloneTree();
        lightMaterialFix(gpLight);
        tgDoorA.addChild(src.tgDoorA.cloneTree());
        tgDoorB.addChild(src.tgDoorB.cloneTree());
        addChild(gpLight);
        addChild(tgDoorA);
        addChild(tgDoorB);
    }

    public int getCurrentState() {
        return currentState;
    }
    
    public void open(){
        if (currentState==DOOR_CLOSED)
            currentState=DOOR_OPENING;
    }
    public void close(){
        if (currentState==DOOR_OPENED)
            currentState=DOOR_CLOSING;
    }
    
    private void actionPreform(double Step){
        if (currentState == DOOR_OPENED || currentState == DOOR_CLOSED)
            return;

        if (currentState == DOOR_OPENING){

            if (this.step >2){
                currentState = DOOR_OPENED;
                t3dDoorA.set(new Vector3d(-0.775,0,0.05));
                t3dDoorB.set(new Vector3d(0.775,0,0.05));
                this.step = 0;
                setLight(1);

            }else{
                if (this.step<0.5){
                    t3dDoorA.set(new Vector3d(-0.3875*step/2 ,0,
                            0.10*step));
                    t3dDoorB.set(new Vector3d(0.3875*step/2 ,0,
                            0.10*step));
                }else{
                    t3dDoorA.set(new Vector3d(-0.3875*(step-0.25)*8/7,0,
                            0.05));
                    t3dDoorB.set(new Vector3d(0.3875*(step-0.25)*8/7,0,
                            0.05));
                }
                this.step+= Step;
                setLight(2);
            }
            tgDoorA.setTransform(t3dDoorA);
            tgDoorB.setTransform(t3dDoorB);
            
        }else if(currentState == DOOR_CLOSING){
            if (this.step >6){
                currentState = DOOR_CLOSED;
                myTrain.doorsClose();
                t3dDoorA.set(new Vector3d(0,0,0));
                t3dDoorB.set(new Vector3d(0,0,0));
                this.step = 0;
                setLight(0);
            }else{
                setLight(2);
                if (step<4){
                    //Beep Only
                }/*else if (step >=4 && step <5){
                    t3dDoorA.set(new Vector3d(-0.775+0.625*(step-4),0,0));
                    t3dDoorB.set(new Vector3d(0.775-0.625*(step-4),0,0));
                }*/else if (step >=4 && step <5.6){
                    t3dDoorA.set(new Vector3d(-0.775+0.7*(step-4)/1.6,0,0.05));
                    t3dDoorB.set(new Vector3d(0.775-0.7*(step-4)/1.6,0,0.05));
                }else{
                    t3dDoorA.set(new Vector3d(-0.075+0.075*(step-5.6)/0.4,0,
                            0.05-0.05*(step-5.6)/0.4));
                    t3dDoorB.set(new Vector3d(0.075-0.075*(step-5.6)/0.4,0,
                            0.05-0.05*(step-5.6)/0.4));
                }
                this.step+= Step;
            }
            tgDoorA.setTransform(t3dDoorA);
            tgDoorB.setTransform(t3dDoorB);
        }
    }
    
    @Override
    public void invoke(double Step) {
        actionPreform(Step);
    }
    
    private void setLight(int type){        //0-OFF 1-ON 2-FLASH
        ColoringAttributes caLight=new ColoringAttributes();
        switch (type){
            case 0:
                caLight.setColor(new Color3f(0.7f,0.7f,0.7f));
                break;
            case 1:
                caLight.setColor(new Color3f(1,150f/255f,200f/255f));
                break;
            case 2:
                if ((step -(int)step)>=0.5){
                    caLight.setColor(new Color3f(1,150f/255f,200f/255f));
                }else{
                    caLight.setColor(new Color3f(0.7f,0.7f,0.7f));
                }
                break;
        }
        appLight.setColoringAttributes(caLight);
    }

    private void lightMaterialFix(Group gpLight) {
        for (int i = 0; i < gpLight.numChildren(); i++) {
            Node n = gpLight.getChild(i);
            if (n instanceof Group)
                lightMaterialFix((Group)n);
            if (n instanceof Shape3D) {
                Shape3D shape = (Shape3D) n;
                Appearance app = new Appearance();
                Material matLight=new Material();
                matLight.setLightingEnable(false);
                shape.setAppearance(app);
                app.setMaterial(matLight);
               
                TextureAttributes textAtt = new TextureAttributes();
                textAtt.setTextureMode(TextureAttributes.REPLACE);
               
                ColoringAttributes caLight=new ColoringAttributes();
                caLight.setColor(new Color3f(0.7f,0.7f,0.7f));
                app.setColoringAttributes(caLight);
                
                app.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE);
                app.setTextureAttributes(textAtt);
                appLight=app;
                //System.err.println("App");
            }
        }
    }
     private void defColorMaterialSet(Group gpLight) {
        for (int i = 0; i < gpLight.numChildren(); i++) {
            Node n = gpLight.getChild(i);
            if (n instanceof Group)
                defColorMaterialSet((Group)n);
            if (n instanceof Shape3D) {
                Shape3D shape = (Shape3D) n;
                Appearance app = shape.getAppearance();
                Material mat = app.getMaterial();
                
                    //System.err.println(shape.getName());

                if (shape.getName().startsWith(
                        myTrain.MyDesc.DefColorMaterialName)){
                    mat.setAmbientColor(myTrain.MyDesc.DefColor);
                    mat.setDiffuseColor(myTrain.MyDesc.DefColor);
                    //System.err.println(shape.getName());
                }
            }
        }
    }
}
